#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
#include <arpa/inet.h>
#include <string.h>

#define SUPER_BLOCK_OFFSET 1024 // 超级块的偏移量
#define BLOCK_SIZE_BASE 1024 // 块大小的基数
#define GROUP_DESC_OFFSET 4096 // 组描述符的偏移量

// 定义超级块结构体
struct ext_super_block {
    uint32_t s_inodes_count;        // inode节点数
    uint32_t s_blocks_count;        // 总块数
    uint32_t s_r_blocks_count;      // 保留块数
    uint32_t s_free_blocks_count;   // 空闲块数
    uint32_t s_free_inodes_count;   // 空闲inode节点数
    uint32_t s_log_block_size;      // 数据块大小的对数值
    uint32_t s_inode_size;          // inode大小
    uint32_t s_block_group_nr;      // 块组号
    uint32_t s_feature_compat;      
};

// 定义组描述符结构体
struct ext_group_desc {
    uint32_t bg_block_bitmap;      // 块位图所在块号
    uint32_t bg_inode_bitmap;      // inode位图所在块号
    uint32_t bg_inode_table;       // inode表起始块号
    uint16_t bg_free_blocks_count; // 空闲块数
    uint16_t bg_free_inodes_count; // 空闲inode数
};

// 定义inode结构体
struct ext_inode {
    uint16_t    i_mode;     // 文件模式
    uint16_t    i_uid;      // 用户ID
    uint32_t    i_size;     // 文件大小
};

// 检查文件是否是块设备文件
int is_block_device(const char *filename) {
    struct stat st;
    if (stat(filename, &st) < 0) {
        perror("stat 错误");
        return -1;
    }
    return S_ISBLK(st.st_mode);
}
//读取块信息
unsigned char *read_block(int fd, uint32_t block_number, int block_size) {
    off_t offset = (off_t)block_number * block_size;
    unsigned char *block = (unsigned char *)malloc(block_size);
    if (lseek(fd, offset, SEEK_SET) < 0 || read(fd, block, block_size) < 0) {
        perror("Error reading block");
        free(block);
        return NULL;
    }
    return block;
}

// 打印超级块信息
void print_super_block(struct ext_super_block *sb) {
    printf("超级块信息\n");
    printf("文件系统类型标识: %u\n", sb->s_feature_compat);
    printf("文件系统大小: %u\n", sb->s_blocks_count);
    printf("数据块大小: %u\n", BLOCK_SIZE_BASE << sb->s_log_block_size);
    printf("inode大小: %u\n", sb->s_inode_size);
    printf("块组大小: %u\n", sb->s_blocks_count / sb->s_block_group_nr);
    printf("总块数: %u\n", sb->s_blocks_count);
    printf("inode节点数: %u\n", sb->s_inodes_count);
    printf("空闲块数: %u\n", sb->s_free_blocks_count);
}

// 打印位图数据
void print_bitmap(unsigned char *bitmap, int block_size) {
    for (int i = 0; i < block_size; i++) {
        for (int j = 0; j < 8; j++) {
            if (bitmap[i] & (1 << j))
                printf("1");
            else
                printf("0");
        }
        printf(" ");
    }
    printf("\n");
}

// 打印组描述符信息
void print_group_desc(struct ext_group_desc *gd, int fd, int block_size) {
    printf("组描述符信息\n");
    printf("块位图所在块号: %u\n", gd->bg_block_bitmap);
    printf("inode位图所在块号: %u\n", gd->bg_inode_bitmap);
    printf("inode表起始块号: %u\n", gd->bg_inode_table);
    printf("空闲块数: %u\n", gd->bg_free_blocks_count);
    printf("空闲inode数: %u\n", gd->bg_free_inodes_count);

    printf("块位图信息:\n");
    unsigned char *block_bitmap = read_block(fd, gd->bg_block_bitmap, block_size);
    if (block_bitmap == NULL) {
        fprintf(stderr, "读取块位图失败\n");
        exit(EXIT_FAILURE);
    }
    print_bitmap(block_bitmap, block_size);
    free(block_bitmap);

    printf("inode位图信息:\n");
    unsigned char *inode_bitmap = read_block(fd, gd->bg_inode_bitmap, block_size);
    if (inode_bitmap == NULL) {
        fprintf(stderr, "读取inode位图失败\n");
        exit(EXIT_FAILURE);
    }
    print_bitmap(inode_bitmap, block_size);
    free(inode_bitmap);
}

// 打印inode信息
void print_inode(struct ext_inode *inode) {
    char buffer1[80];
    char buffer2[80];
    char buffer3[80];
    printf("inode数据项信息\n");
    printf("文件模式: %u\n", inode->i_mode);
    printf("用户ID: %u\n", inode->i_uid);
    printf("文件大小: %u\n", inode->i_size);
}

int main(int argc, char **argv) {
    int fd;
    struct ext_super_block superblock;
    struct ext_group_desc
        group_desc; // 组描述符
    struct ext_inode inode; // inode

    if (argc != 2) {
        fprintf(stderr, "使用方法: %s <设备>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    // 检查参数是否是一个有效的块设备文件
    if (!is_block_device(argv[1])) {
        fprintf(stderr, "%s 不是一个有效的块设备文件\n", argv[1]);
        exit(EXIT_FAILURE);
    }

    // 打开块设备文件
    fd = open(argv[1], O_RDONLY);
    if (fd < 0) {
        perror("无法打开块设备");
        exit(EXIT_FAILURE);
    }

    // 读取超级块信息
    unsigned char *superblock_data = read_block(fd, SUPER_BLOCK_OFFSET / BLOCK_SIZE_BASE, BLOCK_SIZE_BASE);
    if (superblock_data == NULL) {
        fprintf(stderr, "读取超级块错误\n");
        close(fd);
        exit(EXIT_FAILURE);
    }
    memcpy(&superblock, superblock_data, sizeof(superblock));
    free(superblock_data);

    // 计算数据块的大小
    int block_size = BLOCK_SIZE_BASE << superblock.s_log_block_size;

    // 打印超级块信息
    print_super_block(&superblock);

    // 读取组描述符信息
    unsigned char *group_desc_data = read_block(fd, GROUP_DESC_OFFSET / block_size, block_size);
    if (group_desc_data == NULL) {
        fprintf(stderr, "读取组描述符错误\n");
        close(fd);
        exit(EXIT_FAILURE);
    }
    memcpy(&group_desc, group_desc_data, sizeof(group_desc));
    free(group_desc_data);

    // 打印组描述符信息
    print_group_desc(&group_desc, fd, block_size);

    // 读取inode表信息
    unsigned char *inode_data = read_block(fd, group_desc.bg_inode_table, block_size);
    if (inode_data == NULL) {
        fprintf(stderr, "读取inode表错误\n");
        close(fd);
        exit(EXIT_FAILURE);
    }
    memcpy(&inode, inode_data, sizeof(inode));
    free(inode_data);

    // 打印第一个inode的信息
    print_inode(&inode);

    // 关闭块设备文件
    close(fd);

    return 0;
}
